package com.tbit.uqbike.client.remote.adapay;

import com.alibaba.fastjson.JSON;
import com.huifu.adapay.Adapay;
import com.huifu.adapay.core.exception.BaseAdaPayException;
import com.huifu.adapay.model.*;
import com.tbit.common.exceptions.ExternalException;
import com.tbit.uqbike.client.constant.AdaPayConstant;
import com.tbit.uqbike.client.pojo.newEntity.AdaPayConfig;
import com.tbit.uqbike.client.pojo.newEntity.DivMembers;
import com.tbit.uqbike.client.util.DateTimeUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @Author: chen
 * @Description: 支付工具类
 * @Date: 创建于 14:26 2021/9/2
 */
@Slf4j
public class PaymentUtil {

    /** 格式 accountId.pay_channel */
    public static final String mchConfigKey = "%s-%s";

    public static void initNew(List<AdaPayConfig> adaPayConfigList){
        /**
         * debug 模式，开启后有详细的日志
         */
        Adapay.debug = true;

        /**
         * prodMode 模式，默认为生产模式，false可以使用mock模式
         */
        Adapay.prodMode = true;

        Map<String,MerConfig> configMap = new HashMap<>();
        adaPayConfigList.forEach(adaPayConfig -> {
            String key = getMchConfigKey(adaPayConfig);
            MerConfig merConfig = new MerConfig();
            merConfig.setApiKey(adaPayConfig.getApiKey());
            merConfig.setApiMockKey(adaPayConfig.getMockApiKey());
            merConfig.setRSAPrivateKey(adaPayConfig.getRsaPrivateKey());
            configMap.put(key,merConfig);
        });
        try {
            Adapay.initWithMerConfigs(configMap);
        } catch (Exception e) {
            log.error("汇付初始化商户配置失败，入参：{}，异常信息：{}", JSON.toJSONString(configMap), e);
        }
    }

    public static void init(String apiKey, String mockApiKey, String rsaPrivateKey) {
        /**
         * debug 模式，开启后有详细的日志
         */
        Adapay.debug = true;

        /**
         * prodMode 模式，默认为生产模式，false可以使用mock模式
         */
        Adapay.prodMode = true;

        /**
         * 初始化商户配置，服务器启动前，必须通过该方式初始化商户配置完成
         * apiKey为prod模式的API KEY
         * mockApiKey为mock模式的API KEY
         * rsaPrivateKey为商户发起请求时，用于请求参数加签所需要的RSA私钥
         */
        //String apiKey = "api_live_763345b5-562c-4505-ae01-796a75a65d38";
        //String mockApiKey = "api_test_0ce678b1-241c-427c-a840-e34cda9663a7";
        //String rsaPrivateKey = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBANQwr/nHGAtCawGMatQpw6lzUSTn4Gii2pypD2BrTP12reifVpIu4UmKSBOl28BIRp9xm/n6n7gACBemb3OyD1kituP3Qd4nPUa94iw7gK/5MADtYEdA8NMNz2vPEmT3/70WokgL3g6OATX0o7XXOM8KoO7LtaVqrtF5wiIaxJ7jAgMBAAECgYEAqULlPUQZ4/FpVmTiWreuAp+gXOYy1oUCCfG5+FnfolhnRabE8fs/buBFupaVgv6kh0+i8nd/rNEpo2P6h7nEDwtvcJbptlOqVek9jEDGoPGdMneWXnx6+zNoNbe9/BhJwXj8cA8XQBaNCToRWHnJZ9pp2zaj4OuuxfbHYlX90qECQQD8AI0YIY5b415DlHiKEE70Mhv3DMtuJ/Ze3nuAvBd0wQQsZCPUta4BjhCkWku322S+NwC0ZcxpBAFcaR2Aw3JZAkEA145y99+oIy2//gXd7qLWhjXdkue7ZAd5r4+hwA3oaPWN1pjJp5CCQAN1WleaY/2YMW7tPI/pOijK0YH9YHcbmwJBANxJew1SIAixK/C1c910vh/3QbznYVlM87AgmiOByJtWMti/PRcvLgnL7z5MdI4m6dzhZetMZbCTQMFQXer2bxkCQBuryKxzRKVHcTcNz8CbnMhbz9bU8qRTpVZZLN13q5cVtqCOuoxNK7tF9mGjj0k4u7nU0JWOr9TseaTNeBZTE/MCQQCJIxRWuMCJuP/rdaZbEcpNdCwtuUnQc2lysc3yw5e45rF/pSBdb+1CcqoBA5u4pjaUjmiN/9KkjyAghodd7PaR";
        MerConfig merConfig = new MerConfig();
        merConfig.setApiKey(apiKey);
        merConfig.setApiMockKey(mockApiKey);
        merConfig.setRSAPrivateKey(rsaPrivateKey);
        try {
            Adapay.initWithMerConfig(merConfig);
        } catch (Exception e) {
            log.error("汇付初始化商户配置失败，入参：{}，异常信息：{}", JSON.toJSONString(merConfig), e.getMessage());
            e.printStackTrace();
        }

    }

    /**
     * 创建支付订单
     *
     * @return 创建的支付对象
     * @throws Exception 异常
     */
    public static Map<String, Object> executePayment(AdaPayConfig adaPayConfig, double money, String order_no, String openId, String members, String pay_mode, String remark, String brandName) {
        /**初始化配置*/
//        init(adaPayConfig.getApiKey(), adaPayConfig.getMockApiKey(), adaPayConfig.getRsaPrivateKey());
        //System.out.println("=======execute payment begin=======");
        //创建支付对象的参数，全部参数请参考 https://docs.adapay.tech/api/index.html
        Map<String, Object> paymentParams = new HashMap<>(10);
        // 设置超时时间 单位毫秒 类型 int
        // adapay_connection_request_timeout 类型 int, 单位：毫秒 ms
        // 非必须, 默认 10000 指从连接池获取连接的 timeout
        //paymentParams.put("adapay_connection_request_timeout", 15000);
        // adapay_connect_timeout 单位：毫秒 ms
        // 非必须, 默认 30000 指客户端和服务器建立连接的timeout
        //paymentParams.put("adapay_connect_timeout", 1500);
        // adapay_socket_timeout 单位：毫秒 ms
        // 非必须, 默认 30000 指客户端从服务器读取数据的timeout，超出后会抛出SocketTimeOutException
        //paymentParams.put("adapay_socket_timeout", 1500);

        // 设置网络区域
        // 非必须, 默认 shanghai, 如果要使用其他区域请提交工单备注服务器公网出口IP地址申请开通（如：beijing）
        //paymentParams.put("adapay_region", "beijing");
        paymentParams.put("app_id", adaPayConfig.getAppId());
        paymentParams.put("order_no", order_no);
        paymentParams.put("pay_channel", adaPayConfig.getPay_channel());
        paymentParams.put("pay_amt", String.format("%.2f", money));
        paymentParams.put("notify_url", adaPayConfig.getNotifyUrl());
        paymentParams.put("goods_title", remark);
        paymentParams.put("goods_desc", remark);
        paymentParams.put("time_expire", DateTimeUtil.getNowTimeyyyyMMddHHmmss());

        String time_expire = DateTimeUtil.getNowTimeyyyyMMddHHmmss();
        paymentParams.put("time_expire", time_expire);
        if (members != null && !"".equals(members)) {
            paymentParams.put("div_members", members);
        }
        /**是否是延时分账*/
        if (pay_mode != null) {
            paymentParams.put("pay_mode", pay_mode);
        }/*else{
      paymentParams.put("fee_mode","O");
    }*/
        Map<String, Object> map = new HashMap<>();
        if (AdaPayConstant.PAY_CHANNEL_WXXCX.equals(adaPayConfig.getPay_channel())) {
            map.put("open_id", openId);
        } else if (AdaPayConstant.PAY_CHANNEL_ZFBXCX.equals(adaPayConfig.getPay_channel())) {
            map.put("buyer_id", openId);
        }
        paymentParams.put("expend", map);

        //调用sdk方法，创建支付，得到支付对象
        Map<String, Object> payment = new HashMap<>();
        try {
            log.info("支付交易，请求参数：" + JSON.toJSONString(paymentParams));
            payment = Payment.create(paymentParams, getMchConfigKey(adaPayConfig));
        } catch (BaseAdaPayException e) {
            log.error("汇付创建订单{}异常",order_no,e);
            throw new ExternalException("创建订单失败：商户异常",e.getMessage(),brandName);
        }
        String status = (String) payment.getOrDefault("status","");
        log.info("支付交易，返回参数：" + JSON.toJSONString(payment));
        if (Objects.equals(status,"failed")){
            String errorMsg = (String) payment.getOrDefault("error_msg","");
            throw new ExternalException("创建订单失败：商户异常",errorMsg,brandName);
        }
        //System.out.println("=======execute payment end=======");
        return payment;
    }

    /**
     * 获取汇付初始化配置key
     * @param adaPayConfig 汇付配置
     * @return key
     */
    private static String getMchConfigKey(AdaPayConfig adaPayConfig) {
        return String.format(mchConfigKey, adaPayConfig.getAccountId(), adaPayConfig.getPay_channel());
    }

    /**
     * 延时分账
     *
     * @return 查询的支付对象
     * @throws Exception 异常
     */
    public static Map<String, Object> createConfirm(AdaPayConfig adaPayConfig, String paymentId, String orderNO, Double money,
                                                    List<DivMembers> div_members) {
        /**初始化配置*/
//        init(adaPayConfig.getApiKey(), adaPayConfig.getMockApiKey(), adaPayConfig.getRsaPrivateKey());
        System.out.println("=======create confirm  begin=======");
        Map<String, Object> confirm = new HashMap<>();
        confirm.put("payment_id", paymentId);
        confirm.put("order_no", orderNO);
        confirm.put("confirm_amt", String.format("%.2f", money));
        confirm.put("description", "骑行订单分账");
        confirm.put("div_members", div_members);
        try {
            log.info("创建确认对象" + JSON.toJSONString(confirm));
            confirm = PaymentConfirm.create(confirm, getMchConfigKey(adaPayConfig));
        } catch (BaseAdaPayException e) {
            log.error("创建确认对象异常" + orderNO);
            e.printStackTrace();
        }

        log.info("创建确认对象返回参数：" + JSON.toJSONString(confirm));
        System.out.println("=======create confirm  end=======");
        return confirm;
    }


    /**
     * 聚合支付退款
     *
     * @param adaPayConfig adaPayConfig
     * @param paymentId    支付id
     * @param money        金额
     * @return
     * @throws Exception
     */
    public static Map<String, Object> executeRefund(AdaPayConfig adaPayConfig, String paymentId, Double money, String orderNO,
                                                    String members) {
        /**初始化配置*/
//        init(adaPayConfig.getApiKey(), adaPayConfig.getMockApiKey(), adaPayConfig.getRsaPrivateKey());
        //System.out.println("=======execute refund begin=======");
        Map<String, Object> refundParams = new HashMap<String, Object>(2);
        refundParams.put("refund_amt", String.format("%.2f", money / 100));
        refundParams.put("app_id", adaPayConfig.getAppId());
        refundParams.put("refund_order_no", orderNO);
        refundParams.put("notify_url", adaPayConfig.getNotifyUrl());
        if (members != null && !"".equals(members)) {
            refundParams.put("div_members", members);
        }
        log.info("退款请求参数：" + JSON.toJSONString(refundParams));
        Map<String, Object> refund = null;
        try {
            refund = Refund.create(paymentId, refundParams, getMchConfigKey(adaPayConfig));
        } catch (BaseAdaPayException e) {
            e.printStackTrace();
        }
        log.info("退款返回参数：" + JSON.toJSONString(refund));
        return refund;

    }


    /**
     * 创建撤销对象 延时分账未分账订单退款使用此方法退款
     *
     * @param paymentId 要查询的支付id
     * @return 查询的支付对象
     * @throws Exception 异常
     */
    public static Boolean createReverse(AdaPayConfig adaPayConfig, String paymentId, Double money, String orderNO) {
        //System.out.println("=======create Reverse  begin=======");
        /**初始化配置*/
//        init(adaPayConfig.getApiKey(), adaPayConfig.getMockApiKey(), adaPayConfig.getRsaPrivateKey());
        Map<String, Object> reverse = new HashMap<>();
        reverse.put("payment_id", paymentId);
        reverse.put("order_no", orderNO);
        reverse.put("app_id", adaPayConfig.getAppId());
        reverse.put("reverse_amt", String.format("%.2f", money / 100));
        reverse.put("notify_url", adaPayConfig.getNotifyUrl());
        try {
            log.info("创建撤销对象" + JSON.toJSONString(reverse));
            reverse = PaymentReverse.create(reverse, getMchConfigKey(adaPayConfig));
            if (reverse.get("status").equals(AdaPayConstant.PAY_STATUS_PENDING) || reverse.get("status").equals(AdaPayConstant.PAY_STATUS_SUCCEEDED)) {
                return true;
            }
        } catch (BaseAdaPayException e) {
            e.printStackTrace();
        }
        log.info("创建撤销对象返回参数：" + JSON.toJSONString(reverse));
        //System.out.println("=======create Reverse  end=======");
        return false;
    }


    /**
     * 临时退款
     *
     * @param paymentId   支付id
     * @param appid       账号id
     * @param money       金额（元）
     * @param div_members 分账账号
     * @return
     * @throws Exception
     */
    public static Boolean executeRefundTest(String paymentId, String appid, String money, String div_members) throws Exception {
        System.out.println("=======execute refund begin=======");
        Map<String, Object> refundParams = new HashMap<String, Object>(2);
        refundParams.put("refund_amt", money);
        refundParams.put("app_id", appid);
        if (div_members != null) {
            refundParams.put("div_members", div_members);
        }
        refundParams.put("refund_order_no", "jsdk_refund_" + System.currentTimeMillis());
        System.out.println("退款请求参数：" + JSON.toJSONString(refundParams));
        Map<String, Object> refund = Refund.create(paymentId, refundParams);
        System.out.println("退款返回参数：" + JSON.toJSONString(refund));
        System.out.println("=======execute refund end=======");
        if (refund.get("status").equals(AdaPayConstant.PAY_STATUS_PENDING) || refund.get("status").equals(AdaPayConstant.PAY_STATUS_SUCCEEDED)) {
            return true;
        }
        return false;
    }

    public static void main(String[] args) {
        System.out.println(String.format(mchConfigKey, "accountId", "pay_channel"));
    }
}
